#include <buola/gui.h>

#include <buola/algorithm/comparison.h>

#include <buola/widgets/ceditbox.h>
#include <buola/widgets/cnumbox.h>
#include <buola/widgets/ctheme.h>

namespace buola { namespace gui {

CNumBox::CNumBox()
    :   CEditBox()
    ,   mStep(1)
{
    mInsideUp=false;
    mInsideDown=false;
    mPressedUp=false;
    mPressedDown=false;

    SetValue(0);
    SetStyleBit(STYLE_NUMERIC);
}

CNumBox::~CNumBox()
{
}

void CNumBox::GetPropertyNames(std::vector<std::string> &pNames)
{
    pNames.push_back("value");

    CEditBox::GetPropertyNames(pNames);
}

void CNumBox::SetProperty(const std::string &p,const UAny &v)
{
    if(iequals(p,"value"))
    {
        SetValue(v.Get<int>());
    }
    else
    {
        CEditBox::SetProperty(p,v);
    }
}

void CNumBox::GetProperty(const std::string &p,UAny &v)
{
    if(iequals(p,L"value"))
    {
        v.Set<int>(GetValue());
    }
    else
    {
        CEditBox::GetProperty(p,v);
    }
}

void CNumBox::SetValue(double pValue)
{
    if(GetStyle(STYLE_DOUBLE))
        SetCaption(to_wstring(pValue));
    else
        SetCaption(to_wstring((int)pValue));
}

int64_t CNumBox::GetValue()
{
    if(GetStyle(STYLE_DOUBLE))
        return (int64_t)to_<double>(mCaption);
    else
        return to_<int64_t>(mCaption);
}

double CNumBox::GetDoubleValue()
{
    return to_<double>(mCaption);
}

void CNumBox::SetStep(double pStep)
{
    mStep=pStep;
}

///////////////////// Event handling //////////////////////

void CNumBox::OnKeyDown(const CKeyEvent &pE)
{
    if(pE.mKey==KEY_UP)
    {
        SetValue(GetDoubleValue()+mStep);
        eNumChange();
    }
    if(pE.mKey==KEY_DOWN)
    {
        SetValue(GetDoubleValue()-mStep);
        eNumChange();
    }
    else
    {
        CEditBox::OnKeyDown(pE);
    }
}

void CNumBox::OnStyleChanged(TStyle pOld)
{
    if((pOld^GetStyle())&STYLE_FAKE)
    {
    }

    CEditBox::OnStyleChanged(pOld);
}

void CNumBox::OnExpose(const CExposeEvent &pE)
{
    CEditBox::OnExpose(pE);
    CTheme::EDrawStyle lFlags=CTheme::DRAW_NONE;
    if(mInsideUp)
        lFlags|=CTheme::DRAW_UP;
    else if(mInsideDown)
        lFlags|=CTheme::DRAW_DOWN;

    get_default_theme()->DrawNumBox(pE.mGC,this,lFlags);
}

void CNumBox::OnButtonUp(const CMouseEvent &pE)
{
    CEditBox::OnButtonUp(pE);
}

void CNumBox::OnButtonDown(const CMouseEvent &pE)
{
    if(mInsideUp)
    {
        SetValue(GetDoubleValue()+mStep);
        eNumChange();
    }
    else if(mInsideDown)
    {
        SetValue(GetDoubleValue()-mStep);
        eNumChange();
    }
    else
    {
        CEditBox::OnButtonDown(pE);
    }
}

void CNumBox::OnMouseMove(const CMouseEvent &pE)
{
    CRect_d lUp(Size().x-12,0,Size().x,Size().y/2);
    CRect_d lDown(Size().x-12,Size().y/2,Size().x,Size().y);
    if(lUp.Contains(pE.mPoint))
    {
        if(!mInsideUp)
        {
            mInsideUp=true;
            mInsideDown=false;
            SetPointer(CPointer::STOCK_DEFAULT);

            Refresh();
        }
    }
    else if(lDown.Contains(pE.mPoint))
    {
        if(!mInsideDown)
        {
            mInsideDown=true;
            mInsideUp=false;
            SetPointer(CPointer::STOCK_DEFAULT);

            Refresh();
        }
    }
    else
    {
        if(mInsideUp||mInsideDown)
        {
            mInsideUp=false;
            mInsideDown=false;
            SetPointer(CPointer::STOCK_TEXT);

            Refresh();
        }
    }

    CEditBox::OnMouseMove(pE);
}

void CNumBox::OnMouseOut(const CMouseEvent &pE)
{
    if(mInsideUp||mInsideDown)
    {
        mInsideUp=false;
        mInsideDown=false;
        SetPointer(CPointer::STOCK_TEXT);

        Refresh();
    }
}

void CNumBox::OnFocusOut(const CFocusEvent &pE)
{
    SetValue(GetDoubleValue());
    CEditBox::OnFocusOut(pE);
}

void CNumBox::OnEnter()
{
    SetValue(GetDoubleValue());
    CEditBox::OnEnter();
}

/*namespace gui*/ } /*namespace buola*/ }
